package com.example.a14;

import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class A14Application {

    public static void main(String[] param) {
        Proxy proxy = new Proxy();
        Target target = new Target();
        proxy.setMethodInterceptor(new MethodInterceptor() {
            @Override
            public Object intercept(Object p, Method method, Object[] args,
                                    MethodProxy methodProxy) throws Throwable {
                System.out.println("before");

                // ⬇️调用目标方法(三种)
//                Object result = method.invoke(target, args);// ⬅️反射调用
                // FastClass
//                Object result = methodProxy.invoke(target, args); // ⬅️非反射调用, 结合目标用
                Object result = methodProxy.invokeSuper(p, args);// // ⬅️非反射调用, 结合代理用

                return result;

            }
        });

        // ⬇️调用代理方法

        proxy.save();
        proxy.save(1);
        proxy.save(2L);

        /*
            小结:
                1. 当调用 MethodProxy 的 invoke 或 invokeSuper 方法时, 会动态生成两个类
                    a. ProxyFastClass 配合代理对象一起使用, 避免反射
                    b. TargetFastClass 配合目标对象一起使用, 避免反射 (Spring 用的这种)
                2. TargetFastClass 记录了 Target 中方法与编号的对应关系
                    a. save(long)   编号 2
                    b. save(int)    编号 1
                    c. save()       编号 0
                    d. 首先根据方法名和参数个数、类型, 用 switch 和 if 找到这些方法编号
                    e. 然后再根据编号去调用目标方法, 又用了一大堆 switch 和 if, 但避免了反射
                3. ProxyFastClass 记录了 Proxy 中方法与编号的对应关系，不过 Proxy 额外提供了下面几个方法
                    a. saveSuper(long)   编号 2，不增强, 仅是调用 super.save(long)
                    b. saveSuper(int)    编号 1，不增强, 仅是调用 super.save(int)
                    c. saveSuper()       编号 0，不增强, 仅是调用 super.save()
                    d. 查找方式与 TargetFastClass 类似
                4. 为什么有这么麻烦的一套东西呢？
                    a. 避免反射, 提高性能, 代价是一个代理类配两个 FastClass 类, 代理类中还得增加仅调用 super 的一堆方法
                    b. 用编号处理方法对应关系比较省内存, 另外, 最初获得方法顺序是不确定的, 这个过程没法固定死
         */
    }
}
